//
// Created by Ctzzz on 2024/4/28.
//

#include <jni.h>
#include "MyGLRenderContext.h"

#define NATIVE_RENDER_CLASS_NAME "com/catazy/wanandroid/ndkdemo/MyNativeRender"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * 初始化
 * @param env
 * @param instance
 */
JNIEXPORT void JNICALL native_OnInit(JNIEnv *env, jobject instance) {
    MyGLRenderContext::GetInstance();
}

/**
 * 释放
 * @param env
 * @param instance
 */
JNIEXPORT void JNICALL native_OnUnInit(JNIEnv *env, jobject instance) {
    MyGLRenderContext::DestroyInstance();
}

/**
 * 设置图像数据
 * @param env
 * @param instance
 * @param format
 * @param width
 * @param height
 * @param imageData
 */
JNIEXPORT void JNICALL
native_SetImageData(JNIEnv *env, jobject instance, jint format, jint width, jint height,
                    jbyteArray imageData) {
    int len = env->GetArrayLength(imageData);
    uint8_t *buf = new uint8_t[len];
    env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte *>(buf));
    MyGLRenderContext::GetInstance()->SetImageData(format, width, height, buf);
    delete[] buf;
    env->DeleteLocalRef(imageData);
}

/**
 * 设置参数
 * @param env
 * @param instance
 * @param paramType
 * @param value
 */
JNIEXPORT void JNICALL
native_SetParamsInt(JNIEnv *env, jobject instance, jint paramType, jint value) {
    MyGLRenderContext::GetInstance()->SetParamsInt(paramType, value);
}

/**
 * 创建
 * @param env
 * @param instance
 */
JNIEXPORT void JNICALL native_OnSurfaceCreated(JNIEnv *env, jobject instance) {
    MyGLRenderContext::GetInstance()->OnSurfaceCreated();
}

/**
 * 改变
 * @param env
 * @param instance
 * @param width
 * @param height
 */
JNIEXPORT void JNICALL
native_OnSurfaceChanged(JNIEnv *env, jobject instance, jint width, jint height) {
    MyGLRenderContext::GetInstance()->OnSurfaceChanged(width, height);
}

/**
 * 绘制
 * @param env
 * @param instance
 */
JNIEXPORT void JNICALL native_OnDrawFrame(JNIEnv *env, jobject instance) {
    MyGLRenderContext::GetInstance()->OnDrawFrame();
}

#ifdef __cplusplus
}
#endif


static JNINativeMethod g_RenderMethods[] = {
        {"native_OnInit",             "()V",       (void *)(native_OnInit)},
        {"native_OnUnInit",           "()V",       (void *)(native_OnUnInit)},
        {"native_SetImageData",       "(III[B)V",  (void *)(native_SetImageData)},
        {"native_SetParamsInt",       "(II)V",     (void *)(native_SetParamsInt)},
        {"native_OnSurfaceCreated",   "()V",       (void *)(native_OnSurfaceCreated)},
        {"native_OnSurfaceChanged",   "(II)V",     (void *)(native_OnSurfaceChanged)},
        {"native_OnDrawFrame",        "()V",       (void *)(native_OnDrawFrame)},
};

/**
 * 注册方法
 * @param env
 * @param className
 * @param methods
 * @param methodNum
 * @return
 */
static int RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodNum)
{
    LOGCATE("RegisterNativeMethods");
    jclass clazz = env->FindClass(className);
    if (clazz == NULL)
    {
        LOGCATE("RegisterNativeMethods fail. clazz == NULL");
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, methods, methodNum) < 0)
    {
        LOGCATE("RegisterNativeMethods fail");
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

/**
 * 取消注册方法
 * @param env
 * @param className
 */
static void UnregisterNativeMethods(JNIEnv *env, const char *className)
{
    LOGCATE("UnregisterNativeMethods");
    jclass clazz = env->FindClass(className);
    if (clazz == NULL)
    {
        LOGCATE("UnregisterNativeMethods fail. clazz == NULL");
        return;
    }
    if (env != NULL)
    {
        env->UnregisterNatives(clazz);
    }
}

/**
 * JNI_OnLoad
 * @param vm
 * @param reserved
 * @return
 */
extern "C" jint JNI_OnLoad(JavaVM *jvm, void *p)
{
    LOGCATE("===== JNI_OnLoad =====");
    jint jniRet = JNI_ERR;
    JNIEnv *env = NULL;
    if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return jniRet;
    }

    jint regRet = RegisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME, g_RenderMethods,
                                        sizeof(g_RenderMethods) /
                                        sizeof(g_RenderMethods[0]));
    if (regRet != JNI_TRUE)
    {
        return JNI_ERR;
    }

    return JNI_VERSION_1_6;
}

/**
 * JNI_OnUnload
 * @param vm
 * @param reserved
 */
extern "C" void JNI_OnUnload(JavaVM *jvm, void *p)
{
    JNIEnv *env = NULL;
    if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return;
    }

    UnregisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME);
}